package com.chuangsi.common.utils;



import com.alibaba.fastjson2.JSONObject;
import com.chuangsi.common.enums.EsignRequestType;
import com.chuangsi.common.exception.ServiceException;
import com.chuangsi.common.utils.esign.EsignHttpHelper;
import com.chuangsi.common.utils.esign.EsignHttpResponse;
import com.chuangsi.project.admin.domain.Seal;
import com.chuangsi.project.admin.dto.app.esign.ResESignDownloadDto;
import com.chuangsi.project.admin.dto.app.esign.ResESignGetSignFlowDetailDto;
import com.chuangsi.project.admin.dto.esign.*;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangshengming
 * @date 2023/4/6
 */
public class SignatureUtils {

    private final static String method_post = "POST";
    private final static String method_get = "GET";
    private final static String accept = "*/*";
    private final static String contentType = "application/json; charset=UTF-8";
    private final static String signature = "Signature";
    private final static String X_Tsign_Open_App_Id = "X-Tsign-Open-App-Id";
    private final static String X_Tsign_Open_Auth_Mode = "X-Tsign-Open-Auth-Mode";
    private final static String X_Tsign_Open_Ca_Timestamp = "X-Tsign-Open-Ca-Timestamp";
    private final static String Accept = "Accept";
    private final static String Content_Type = "Content-Type";
    private final static String X_Tsign_Open_Ca_Signature = "X-Tsign-Open-Ca-Signature";
    private final static String Content_MD5 = "Content-MD5";
    private final static String Header_Date = "Date";


//    public final static String AppId = "7438958665";
//    public final static String AppSecret = "43e82e263d943043fa6a1e2af35a0a7d";

    //    public final static String TestUrl = "https://smlopenapi.esign.cn";
    public final static String TestUrl = "https://openapi.esign.cn";

//    /////////////////////////////////////////重庆创虹汽车服务有限公司//////////////////////////////////////////
//    public final static String AppId = "5111808481";
//    public final static String AppSecret = "dd0fb500f938a0aba0090c24548563ce";
//    //经办人账号id
//    public final static String PSNID = "a6dfddfa948041ceb12fe8818329c721";
//    //机构id
//    public final static String ORGID = "18ee0195c999492c962c19f6aa25d01f";
//    //印章id
//    public final static String ASSIGNEDSEALID = "34998fa0-114a-48fd-bb29-038670aa9ec8";
//    /////////////////////////////////////////重庆创虹汽车服务有限公司//////////////////////////////////////////


//    /////////////////////////////////////////重庆创思汽车服务有限公司//////////////////////////////////////////
//    public final static String AppId = "5111808481";
//    public final static String AppSecret = "dd0fb500f938a0aba0090c24548563ce";
//    //经办人账号id
//    public final static String PSNID = "a6dfddfa948041ceb12fe8818329c721";
//    //机构id
//    public final static String ORGID = "a9d5a6d6e1244d509425e9221e72560e";
//    //印章id
//    public final static String ASSIGNEDSEALID = "1841c0d5-dd5d-487e-b2c6-18ddd28a5170";
//    /////////////////////////////////////////重庆创思汽车服务有限公司//////////////////////////////////////////



//    public static void main(String[] args) {
////        // 请求签名鉴权-POST请求
////        testPost(appId, appKey, host);
////
////        // 请求签名鉴权-GET请求
////        testGet(appId, appKey, host);
//
//        ReqESignStartSignDto r = new ReqESignStartSignDto();
//        List<ReqESignStartSignDto.DocsDto> list = new ArrayList<>();
//        ReqESignStartSignDto.DocsDto docsDto = new ReqESignStartSignDto.DocsDto();
//        docsDto.setFileId("0c16261aaaf64fbeac4be046bfbe9ddd");
//        list.add(docsDto);
//        r.setDocs(list);
//        ReqESignStartSignDto.SignFlow signFlow = new ReqESignStartSignDto.SignFlow();
//        signFlow.setSignFlowTitle("标题");
//        r.setSignFlowConfig(signFlow);
//        startSign(r,null);
//        //showSignFlowUrl();
//    }

    /***
     *  请求文件上传地址和文件id
     *
     */
    public static ResESignUploadFileDto getUploadUrl(ReqESignUploadFileDto req, Seal seal) {

        String apiUrl = "/v3/files/file-upload-url";

        try {
            /** 1.构建POST请求Body体 */
            JSONObject body = new JSONObject();
            body.put("contentMd5", req.getContentMd5());
            body.put("contentType", req.getContentType());
            body.put("fileName", req.getFileName());
            body.put("fileSize", req.getFileSize());
            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // MD5加密
            String md5 = doContentMD5(body.toString());
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, apiUrl, method_post), seal.getAppSecret());
            System.out.println("sign： " + getSignStr(date, md5, apiUrl, method_post));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, seal.getAppId());
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            /** 4.发送POST请求*/
            String postUrl = TestUrl + apiUrl;
            String result = sendPOST(postUrl, body.toString(), header, "UTF-8");

            System.out.println("请求参数"+body.toString());


//            System.out.println("请求返回信息： " + JSONObject.toJSONString(result));


            ResESignUploadFileDto res = JSONObject.parseObject(result, ResESignUploadFileDto.class);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
//            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
//            System.out.println(msg);
            return null;
        }
    }


    /**
     * 上传文件流
     */
    public static ResESignUploadFileStep2Dto uploadStream(ReqESignUploadFileStep2Dto req){
        String apiUrl = req.getFileUploadUrl();

        try {

            /** 1.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("Content-MD5", req.getContentMd5());
            header.put("Content-Type", "application/octet-stream");

            /** 2.发送PUT请求*/
            String postUrl = apiUrl;
            String result = sendPut(postUrl, req.getStream(), header, "UTF-8");

            System.out.println("请求参数"+req.getStream());


            System.out.println("请求返回信息： " + JSONObject.toJSONString(result));


            ResESignUploadFileStep2Dto res = JSONObject.parseObject(result, ResESignUploadFileStep2Dto.class);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
//            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
//            System.out.println(msg);
            return null;
        }
    }


    public static void main(String[] args) {
        Seal seal = new Seal();
        seal.setAppSecret("f198278dcf4f6c5bd8f9473b6a78ee35");
        seal.setAppId("5111899676");
        ReqGetPositionsDto reqGetPositionsDto = new ReqGetPositionsDto();
        List<String> key = new ArrayList<>();
        key.add("甲方签名");
        key.add("乙方签名");
        reqGetPositionsDto.setKeywords(key);
        reqGetPositionsDto.setFileId("c164e333dba144cb89c9550a1c2c3fac");
        ResGetPositionsDto dat =  getPositions(reqGetPositionsDto, seal);
    }


    /**
     * 根据文件id+关键字获取签章位置坐标
     */
    public static ResGetPositionsDto getPositions(ReqGetPositionsDto req, Seal seal){
        String apiUrl = "/v3/files/"+req.getFileId()+"/keyword-positions";
        try {
            /** 1.构建POST请求Body体 */
            JSONObject body = new JSONObject();
            body.put("keywords", req.getKeywords());
            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";
            /** 2.构建签名字符串 */
            // MD5加密
            String md5 = doContentMD5(body.toString());
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, apiUrl, method_post), seal.getAppSecret());
            System.out.println("sign： " + getSignStr(date, md5, apiUrl, method_post));
            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, seal.getAppId());
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);
            /** 4.发送POST请求*/
            String postUrl = TestUrl + apiUrl;
            String result = sendPOST(postUrl, body.toString(), header, "UTF-8");
            System.out.println("根据文件id+关键字获取签章位置坐标:请求参数"+ body);
            System.out.println("根据文件id+关键字获取签章位置坐标:返回参数"+ JSONObject.toJSONString(result));
            return  JSONObject.parseObject(result, ResGetPositionsDto.class);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据文件id启动签署流程
     */
    public static ResESignStartSignDto startSign(ReqESignStartSignDto req, Seal seal){
        String apiUrl = "/v3/sign-flow/create-by-file";

        try {
            /** 1.构建POST请求Body体 */
            JSONObject body = new JSONObject();
            body.put("docs", req.getDocs());
            body.put("signFlowConfig", req.getSignFlowConfig());
            body.put("signers", req.getSigners());
            body.put("signFlowInitiator",req.getSignFlowInitiator());
            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // MD5加密
            String md5 = doContentMD5(body.toString());
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, apiUrl, method_post), seal.getAppSecret());
            System.out.println("sign： " + getSignStr(date, md5, apiUrl, method_post));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, seal.getAppId());
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            System.out.println("请求参数"+body.toString());
            /** 4.发送POST请求*/
            String postUrl = TestUrl + apiUrl;
            String result = sendPOST(postUrl, body.toString(), header, "UTF-8");




            System.out.println("请求返回信息： " + JSONObject.toJSONString(result));


            ResESignStartSignDto res = JSONObject.parseObject(result, ResESignStartSignDto.class);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
//            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
//            System.out.println(msg);
            return null;
        }
    }


    /**
     * 根据签署流程id获取签署页面链接
     */
    public static ResESignShowSignFlowUrlDto showSignFlowUrl(ReqESignShowSignFlowUrlDto req, Seal seal){
        String apiUrl = "/v3/sign-flow/"+req.getSignFlowId()+"/sign-url";

        try {
            /** 1.构建POST请求Body体 */
            JSONObject body = new JSONObject();
            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // MD5加密
            String md5 = doContentMD5(body.toString());
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, apiUrl, method_post), seal.getAppSecret());
            System.out.println("sign： " + getSignStr(date, md5, apiUrl, method_post));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, seal.getAppId());
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            /** 4.发送POST请求*/
            String postUrl = TestUrl + apiUrl;
            String result = sendPOST(postUrl, body.toString(), header, "UTF-8");

            System.out.println("请求参数"+body.toString());
//            System.out.println("请求返回信息： " + JSONObject.toJSONString(result));
            ResESignShowSignFlowUrlDto res = JSONObject.parseObject(result, ResESignShowSignFlowUrlDto.class);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据签署流程id开启签署
     */
    public static ResResponseDataDto startSignFlow(ReqESignShowSignFlowUrlDto req, Seal seal){
        String apiUrl = "/v3/sign-flow/"+req.getSignFlowId()+"/start";

        try {
            /** 1.构建POST请求Body体 */
            JSONObject body = new JSONObject();
            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // MD5加密
            String md5 = doContentMD5(body.toString());
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, apiUrl, method_post), seal.getAppSecret());
            System.out.println("sign： " + getSignStr(date, md5, apiUrl, method_post));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, seal.getAppId());
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            /** 4.发送POST请求*/
            String postUrl = TestUrl + apiUrl;
            String result = sendPOST(postUrl, body.toString(), header, "UTF-8");

            System.out.println("请求参数"+body.toString());
//            System.out.println("请求返回信息： " + JSONObject.toJSONString(result));
            ResResponseDataDto res = JSONObject.parseObject(result, ResResponseDataDto.class);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 根据签署流程id获取当前签署状态
     * @Parma signFlowId 签署流程id
     */
    public static ResESignGetSignFlowDetailDto getSignFlowDetail(String signFlowId, Seal seal){
        String apiUrl = "/v3/sign-flow/"+signFlowId+"/detail";
        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        String jsonParm = null;
        //请求方法
        EsignRequestType requestType = EsignRequestType.GET;
        //生成签名鉴权方式的的header
        Map<String, String> header = null;
        try {
            header = EsignHttpHelper.signAndBuildSignAndJsonHeader(seal.getAppId(), seal.getAppSecret(),jsonParm,requestType.name(),apiUrl,true);
        } catch (Exception e) {
            throw new ServiceException("请求失败");
        }
        //发起接口请求
        EsignHttpResponse esignHttpResponse = null;
        try {
            esignHttpResponse = EsignHttpHelper.doCommHttp(TestUrl, apiUrl, requestType, jsonParm, header, true);
        } catch (Exception e) {
            throw new ServiceException("请求失败");
        }
        String body = esignHttpResponse.getBody();
        ResESignGetSignFlowDetailDto res = JSONObject.parseObject(body, ResESignGetSignFlowDetailDto.class);
        if(0!=res.getCode()){
            throw new ServiceException("获取流程状态失败");
        }
        return res;

    }


    /**
     * 下载文件
     */
    @SneakyThrows
    public static ResESignDownloadDto getSignDownload(String signFlowId, Seal seal){
        String apiUrl = "/v3/sign-flow/"+signFlowId+"/file-download-url";
        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        String jsonParm = null;
        //请求方法
        EsignRequestType requestType = EsignRequestType.GET;
        //生成签名鉴权方式的的header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(seal.getAppId(),seal.getAppSecret(),jsonParm,requestType.name(),apiUrl,true);
//        发起接口请求
        EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(TestUrl, apiUrl, requestType, jsonParm, header, true);
        String body = esignHttpResponse.getBody();
        ResESignDownloadDto res = JSONObject.parseObject(body, ResESignDownloadDto.class);
        return res;

    }



    /**
     * 查询机构认证信息
     * @param req
     * @return
     */
    public static ResESignOrgAuthDto getOrgAuth(ReqESignOrgAuthDto req,String appId,String appSecret){
        String apiUrl = "/v3/organizations/identity-info";

        try {
            /** 1.构建get请求参数 */
            Map<String,Object> paramsMap = new HashMap<>();
            paramsMap.put("orgName", req.getOrgName());

            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // GET请求时ContentMD5为""
            String md5 = "";
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, getUrlWithPath(apiUrl, paramsMap, false), method_get), appSecret);
            System.out.println("sign： " + getSignStr(date, md5, getUrlWithPath(apiUrl, paramsMap, false), method_get));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, appId);
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            /** 4.发送GET请求*/
            String getUrl = TestUrl + getUrlWithPath(apiUrl, paramsMap, true);
            String result = sendGet(getUrl, header, "UTF-8");
            ResESignOrgAuthDto res = JSONObject.parseObject(result, ResESignOrgAuthDto.class);
             return res;
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
            return null;
        }

    }

    /**
     * 发起认证
     * @param req
     * @return
     */
    public static ResESignGetAuthUrlDto orgAuth(ReqESignGetAuthUrlDto req, Seal seal){
        String apiUrl = "/v3/org-auth-url";

        try {
            /** 1.构建POST请求Body体 */
            JSONObject body = new JSONObject();
            body.put("orgAuthConfig", req.getOrgAuthConfig());
            body.put("authorizeConfig", req.getAuthorizeConfig());
            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // MD5加密
            String md5 = doContentMD5(body.toString());
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, apiUrl, method_post), seal.getAppSecret());
            System.out.println("sign： " + getSignStr(date, md5, apiUrl, method_post));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, seal.getAppId());
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            System.out.println("请求参数"+body.toString());
            /** 4.发送POST请求*/
            String postUrl = TestUrl + apiUrl;
            String result = sendPOST(postUrl, body.toString(), header, "UTF-8");




//            System.out.println("请求返回信息： " + JSONObject.toJSONString(result));


            ResESignGetAuthUrlDto res = JSONObject.parseObject(result, ResESignGetAuthUrlDto.class);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
//            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
//            System.out.println(msg);
            return null;
        }
    }


    /**
     * 查询企业内部印章
     * @param
     * @return
     */
    public static void orgSealList(String orgId,String appId,String appSecret){
        String apiUrl = "/v3/seals/org-own-seal-list";
        try {
            /** 1.构建get请求参数 */
            Map<String,Object> paramsMap = new HashMap<>();
            paramsMap.put("orgId", orgId);
            paramsMap.put("pageNum", 1);
            paramsMap.put("pageSize", 20);

            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // GET请求时ContentMD5为""
            String md5 = "";
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, getUrlWithPath(apiUrl, paramsMap, false), method_get), appSecret);
            System.out.println("sign： " + getSignStr(date, md5, getUrlWithPath(apiUrl, paramsMap, false), method_get));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, appId);
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            /** 4.发送GET请求*/
            String getUrl = TestUrl + getUrlWithPath(apiUrl, paramsMap, true);
            String result = sendGet(getUrl, header, "UTF-8");
            System.err.println(result);
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
        }
    }

    /**
     * 查询企业管理员
     * @param req
     * @return
     */
    public static ResESignQueryAdminDto getOrgAdminInfo(ReqESignQueryAdminDto req,String appId,String appSecret){
        String apiUrl = "/v3/organizations/"+req.getOrgId()+"/administrators";
        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        String jsonParm = null;
        //请求方法
        EsignRequestType requestType = EsignRequestType.GET;
        //生成签名鉴权方式的的header
        Map<String, String> header = null;
        try {
            header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId,appSecret,jsonParm,requestType.name(),apiUrl,true);
        } catch (Exception e) {
            throw new ServiceException("请求失败");
        }
//        发起接口请求
        EsignHttpResponse esignHttpResponse = null;
        try {
            esignHttpResponse = EsignHttpHelper.doCommHttp(TestUrl, apiUrl, requestType, jsonParm, header, true);
        } catch (Exception e) {
            throw new ServiceException("请求失败");
        }
        String body = esignHttpResponse.getBody();
        ResESignQueryAdminDto res = JSONObject.parseObject(body, ResESignQueryAdminDto.class);
        if(0!=res.getCode()){
            throw new ServiceException("获取流程状态失败");
        }
        return res;

    }
        /**
         * 跨企业印章授权
         */

    public static ResESignOrgPrintAuthDto getPrintAuth(ReqESignOrgPrintAuthDto req, Seal seal){
        String apiUrl = "/v3/seals/org-seals/external-auth";

        try {
            /** 1.构建POST请求Body体 */
            JSONObject body = new JSONObject();
            body.put("orgId", req.getOrgId());
            body.put("sealId", req.getSealId());
            body.put("transactorPsnId", req.getTransactorPsnId());
            body.put("authorizedOrgInfo", req.getAuthorizedOrgInfo());
            body.put("effectiveTime", req.getEffectiveTime());
            body.put("expireTime", req.getExpireTime());
            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // MD5加密
            String md5 = doContentMD5(body.toString());
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, apiUrl, method_post), seal.getAppSecret());
            System.out.println("sign： " + getSignStr(date, md5, apiUrl, method_post));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, seal.getAppSecret());
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            System.out.println("请求参数"+body.toString());
            /** 4.发送POST请求*/
            String postUrl = TestUrl + apiUrl;
            String result = sendPOST(postUrl, body.toString(), header, "UTF-8");




//            System.out.println("请求返回信息： " + JSONObject.toJSONString(result));


            ResESignOrgPrintAuthDto res = JSONObject.parseObject(result, ResESignOrgPrintAuthDto.class);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
//            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
//            System.out.println(msg);
            return null;
        }
    }






//////////////////////////////////////////////////以下是通用方法//////////////////////////////////////////////////////////////////////////
    /***
     * 请求签名鉴权-GET请求
     *
     * @param appId
     * @param appKey
     * @param host
     */
    public static void testGet(String appId, String appKey, String host) {
        // 模版管理API-查询PDF文件详情
        String apiUrl = "/v1/files/fileId";

        try {
            /** 1.构建get请求参数 */
            Map<String,Object> paramsMap = new HashMap<>();
            paramsMap.put("thirdPartyUserId", "229");
            paramsMap.put("name", "张三");
            paramsMap.put("idType", "CRED_PSN_CH_IDCARD");
            paramsMap.put("idNumber", "330621");
            paramsMap.put("mobile", "152****4800");
            paramsMap.put("email", "152****800@163.com");

            //输入请求头中的Date,格式需符合RFC822规范, 非必传参数
            String date = "";

            /** 2.构建签名字符串 */
            // GET请求时ContentMD5为""
            String md5 = "";
            // SHA256签名
            String reqSignature = doSignatureBase64(getSignStr(date, md5, getUrlWithPath(apiUrl, paramsMap, false), method_get), appKey);
            System.out.println("sign： " + getSignStr(date, md5, getUrlWithPath(apiUrl, paramsMap, false), method_get));

            /** 3.构建请求头 */
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put(X_Tsign_Open_App_Id, appId);
            header.put(X_Tsign_Open_Auth_Mode, signature);
            header.put(X_Tsign_Open_Ca_Timestamp, String.valueOf(System.currentTimeMillis()));
            header.put(Accept, accept);
            header.put(Content_Type, contentType);
            header.put(X_Tsign_Open_Ca_Signature, reqSignature);
            header.put(Content_MD5, md5);
            header.put(Header_Date, date);

            /** 4.发送GET请求*/
            String getUrl = host + getUrlWithPath(apiUrl, paramsMap, true);
            String result = sendGet(getUrl, header, "UTF-8");
//            JSONObject resultObj = JSONObject.fromObject(result);
//            System.out.println("请求返回信息： " + resultObj.toString());
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
        }
    }

    /**
     * 获取待签名的url,params.key按自然序排序
     * 注意：
     * 1.待签名字符串中的url不需要转码; isUrlEncode = false
     * 2.get请求的url需要转码（服务端接受会出现中文乱码，鉴权签名会过不了） isUrlEncode = true
     * @param url
     * @param paramsMap
     * @param isUrlEncode  是否进行urlEncode转码；
     * @return
     */
    private static String getUrlWithPath(String url, Map<String, Object> paramsMap, boolean isUrlEncode){
        SortedMap<String, Object> sortedMap = new TreeMap<>(paramsMap);

        String params = "?" + sortedMap.entrySet().stream().map(e-> {
            try {
                return e.getKey()+"="+(isUrlEncode? URLEncoder.encode(e.getValue().toString(), "UTF-8"):e.getValue());
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
                return e.getKey()+"="+e.getValue();
            }
        }).collect(Collectors.joining("&"));
        url += params;
        return url;
    }

    /***
     *
     * @param str 待计算的消息
     * @return MD5计算后摘要值的Base64编码(ContentMD5)
     * @throws Exception 加密过程中的异常信息
     */
    private static String doContentMD5(String str) throws Exception {

        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(str.getBytes(StandardCharsets.UTF_8));
        byte[] md5Bytes = md5.digest();
        // 把MD5摘要后的二进制数组md5Bytes使用Base64进行编码（而不是对32位的16进制字符串进行编码）
        return new String(Base64.encodeBase64(md5Bytes), StandardCharsets.UTF_8);
    }

    /**
     * 构建待签名字符串 Post
     * @param contentMD5
     * @param url
     * @return
     */
    private static String getSignStr(String date, String contentMD5, String url, String method){
        String headers = "";
        String newLine = "".equals(headers)?"":"\n";

        return method + "\n" +
                accept + "\n" +
                contentMD5 + "\n" +
                contentType + "\n" +
                date + "\n" +
                headers + newLine +
                url;
    }

    /***
     * 计算请求签名值
     *
     * @param message 待计算的消息
     * @param secret 密钥
     * @return HmacSHA256计算后摘要值的Base64编码
     * @throws Exception 加密过程中的异常信息
     */
    private static String doSignatureBase64(String message, String secret) throws NoSuchAlgorithmException, InvalidKeyException {
        String algorithm = "HmacSHA256";
        Mac hmacSha256 = Mac.getInstance(algorithm);
        byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
        byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);
        hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
        // 使用HmacSHA256对二进制数据消息Bytes计算摘要
        byte[] digestBytes = hmacSha256.doFinal(messageBytes);
        // 把摘要后的结果digestBytes使用Base64进行编码
        return new String(Base64.encodeBase64(digestBytes), StandardCharsets.UTF_8);
    }

//-----------------------------------------Http请求部分-----------------------------------------------

    /***
     * 向指定URL发送GET方法的请求
     *
     * @param apiUrl
     * @param encoding
     * @return
     * @throws Exception
     */
    public static String sendGet(String apiUrl, LinkedHashMap<String, String> headers,
                                 String encoding) throws Exception {
        // 获得响应内容
        String http_RespContent = null;
        HttpURLConnection httpURLConnection = null;
        int http_StatusCode = 0;
        String http_RespMessage = null;
        try {
            System.out.println(">>>> 实际请求Url: " + apiUrl);

            // 建立连接
            URL url = new URL(apiUrl);
            httpURLConnection = (HttpURLConnection) url.openConnection();
            // 需要输出
            httpURLConnection.setDoOutput(true);
            // 需要输入
            httpURLConnection.setDoInput(true);
            // 不允许缓存
            httpURLConnection.setUseCaches(false);
            // HTTP请求方式
            httpURLConnection.setRequestMethod("GET");
            // 设置Headers
            if (null != headers) {
                for (String key : headers.keySet()) {
                    httpURLConnection.setRequestProperty(key, headers.get(key));
                }
            }
            // 连接会话
            httpURLConnection.connect();
            // 获得响应状态(HTTP状态码)
            http_StatusCode = httpURLConnection.getResponseCode();
            // 获得响应消息(HTTP状态码描述)
            http_RespMessage = httpURLConnection.getResponseMessage();
            // 获得响应内容
            if (HttpURLConnection.HTTP_OK == http_StatusCode) {
                // 返回响应结果
                http_RespContent = getResponseContent(httpURLConnection);
            } else {
                // 返回非200状态时响应结果
                http_RespContent = getErrorResponseContent(httpURLConnection);
                String msg =
                        MessageFormat.format("请求失败: Http状态码 = {0} , {1}", http_StatusCode, http_RespMessage);
                System.out.println(msg);
            }
        } catch (UnknownHostException e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (MalformedURLException e) {
            String message = MessageFormat.format("格式错误的URL: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (IOException e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (Exception e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } finally {
            if (null != httpURLConnection) {
                httpURLConnection.disconnect();
            }
        }
        return http_RespContent;
    }

    /***
     * 向指定URL发送POST方法的请求
     *
     * @param apiUrl
     * @param data

     * @param encoding
     * @return
     * @throws Exception
     */
    public static String sendPOST(String apiUrl, String data, LinkedHashMap<String, String> headers,
                                  String encoding) throws Exception {
        // 获得响应内容
        String http_RespContent = null;
        HttpURLConnection httpURLConnection = null;
        int http_StatusCode = 0;
        String http_RespMessage = null;
        try {
            // 建立连接
            URL url = new URL(apiUrl);
            httpURLConnection = (HttpURLConnection) url.openConnection();
            // 需要输出
            httpURLConnection.setDoOutput(true);
            // 需要输入
            httpURLConnection.setDoInput(true);
            // 不允许缓存
            httpURLConnection.setUseCaches(false);
            // HTTP请求方式
            httpURLConnection.setRequestMethod("POST");
            // 设置Headers
            if (null != headers) {
                for (String key : headers.keySet()) {
                    httpURLConnection.setRequestProperty(key, headers.get(key));
                }
            }
            // 连接会话
            httpURLConnection.connect();
            // 建立输入流，向指向的URL传入参数
            DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
            // 设置请求参数
            dos.write(data.getBytes(encoding));
            dos.flush();
            dos.close();
            // 获得响应状态(HTTP状态码)
            http_StatusCode = httpURLConnection.getResponseCode();
            // 获得响应消息(HTTP状态码描述)
            http_RespMessage = httpURLConnection.getResponseMessage();
            // 获得响应内容
            if (HttpURLConnection.HTTP_OK == http_StatusCode) {
                // 返回响应结果
                http_RespContent = getResponseContent(httpURLConnection);
            } else {
                // 返回非200状态时响应结果
                http_RespContent = getErrorResponseContent(httpURLConnection);
                String msg =
                        MessageFormat.format("请求失败: Http状态码 = {0} , {1}", http_StatusCode, http_RespMessage);
                System.out.println(msg);
            }
        } catch (UnknownHostException e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (MalformedURLException e) {
            String message = MessageFormat.format("格式错误的URL: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (IOException e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (Exception e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } finally {
            if (null != httpURLConnection) {
                httpURLConnection.disconnect();
            }
        }
        return http_RespContent;
    }


    public static String sendPut(String apiUrl, byte[] data, LinkedHashMap<String, String> headers,
                                  String encoding) throws Exception {
        // 获得响应内容
        String http_RespContent = null;
        HttpURLConnection httpURLConnection = null;
        int http_StatusCode = 0;
        String http_RespMessage = null;
        try {
            // 建立连接
            URL url = new URL(apiUrl);
            httpURLConnection = (HttpURLConnection) url.openConnection();
            // 需要输出
            httpURLConnection.setDoOutput(true);
            // 需要输入
            httpURLConnection.setDoInput(true);
            // 不允许缓存
            httpURLConnection.setUseCaches(false);
            // HTTP请求方式
            httpURLConnection.setRequestMethod("PUT");
            // 设置Headers
            if (null != headers) {
                for (String key : headers.keySet()) {
                    httpURLConnection.setRequestProperty(key, headers.get(key));
                }
            }
            // 连接会话
            httpURLConnection.connect();
            // 建立输入流，向指向的URL传入参数
            DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
            // 设置请求参数
            dos.write(data);
            dos.flush();
            dos.close();
            // 获得响应状态(HTTP状态码)
            http_StatusCode = httpURLConnection.getResponseCode();
            // 获得响应消息(HTTP状态码描述)
            http_RespMessage = httpURLConnection.getResponseMessage();
            // 获得响应内容
            if (HttpURLConnection.HTTP_OK == http_StatusCode) {
                // 返回响应结果
                http_RespContent = getResponseContent(httpURLConnection);
            } else {
                // 返回非200状态时响应结果
                http_RespContent = getErrorResponseContent(httpURLConnection);
                String msg =
                        MessageFormat.format("请求失败: Http状态码 = {0} , {1}", http_StatusCode, http_RespMessage);
                System.out.println(msg);
            }
        } catch (UnknownHostException e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (MalformedURLException e) {
            String message = MessageFormat.format("格式错误的URL: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (IOException e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } catch (Exception e) {
            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
            Exception ex = new Exception(message);
            ex.initCause(e);
            throw ex;
        } finally {
            if (null != httpURLConnection) {
                httpURLConnection.disconnect();
            }
        }
        return http_RespContent;
    }

    /***
     * 读取HttpResponse响应内容
     *
     * @param httpURLConnection
     * @return
     * @throws UnsupportedEncodingException
     * @throws IOException
     */
    private static String getResponseContent(HttpURLConnection httpURLConnection)
            throws UnsupportedEncodingException, IOException {
        StringBuffer contentBuffer = null;
        BufferedReader responseReader = null;
        try {
            contentBuffer = new StringBuffer();
            String readLine = null;
            responseReader =
                    new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), "UTF-8"));
            while ((readLine = responseReader.readLine()) != null) {
                contentBuffer.append(readLine);
            }
        } finally {
            if (null != responseReader) {
                responseReader.close();
            }
        }
        return contentBuffer.toString();
    }

    /***
     * 读取HttpResponse响应内容
     *
     * @param httpURLConnection
     * @return
     * @throws UnsupportedEncodingException
     * @throws IOException
     */
    private static String getErrorResponseContent(HttpURLConnection httpURLConnection)
            throws UnsupportedEncodingException, IOException {
        StringBuffer contentBuffer = null;
        BufferedReader responseReader = null;
        try {
            contentBuffer = new StringBuffer();
            String readLine = null;
            responseReader =
                    new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream(), "UTF-8"));
            while ((readLine = responseReader.readLine()) != null) {
                contentBuffer.append(readLine);
            }
        } finally {
            if (null != responseReader) {
                responseReader.close();
            }
        }
        return contentBuffer.toString();
    }


    /**
     * @param  {@link String} 文件地址
     * @return
     * @throws
     * @description 获取文件字节流
     * @date 2019年7月10日 上午9:17:00
     * @author 宫清
     */
    public static byte[] getBytes(File file) throws ServiceException {
        FileInputStream fis = null;
        byte[] buffer = null;
        try {
            fis = new FileInputStream(file);
            buffer = new byte[(int) file.length()];
            fis.read(buffer);
        } catch (Exception e) {
           throw new ServiceException("获取文件流失败");
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    throw new ServiceException("获取文件流失败");
                }
            }
        }
        return buffer;
    }


}
